package com.warmheart.core.co.oper;

import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.warmheart.core.co.builder.CoBuilder;
import com.warmheart.core.co.enums.OrderTypeEnum;
import com.warmheart.core.co.enums.SqlLinkTypeEnum;
import com.warmheart.core.co.model.OrderByModel;
import com.warmheart.core.co.model.RelationModel;
import com.warmheart.core.cors.builder.CoRsBuilder;

/**
 * 
 * @ClassName: Co
 * @Description: 该类用作对特殊条件以及排序进行处理
 * @author ZhangJianyang
 * @date 2025-06-16 09:37:02
 *
 * @param <T>
 * @param <E>
 */
public class Co<T extends CoRsBuilder<?, ?>, E extends CoBuilder<T>> {

    private final E e;

    private final T t;

    private final String field;

    private final Boolean isDate;

    private final String format;

    public Co(E e, String field) {
        this.isDate = false;
        this.format = null;
        this.e = e;
        this.t = this.e.core();
        this.field = field;
    }

    public Co(E e, String field, String format) {
        this.isDate = true;
        this.format = format;
        this.e = e;
        this.t = this.e.core();
        this.field = field;
    }

    public String fetchField() {
        return this.field;
    }
    
    public Boolean checkDate() {
        return this.isDate;
    }

    public String fetchFormat() {
        return this.format;
    }

    public <F> E eq(F value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "=", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E notEq(F value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "!=", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E lt(F value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "<", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E lte(F value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "<=", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E gt(F value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, ">", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E gte(F value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, ">=", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public E preLike(String value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "like", value, this.isDate, this.format, sqlLinkTypeEnum, "pre"));
        return this.e;
    }

    public E sufLike(String value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "like", value, this.isDate, this.format, sqlLinkTypeEnum, "suf"));
        return this.e;
    }

    public E bothLike(String value, SqlLinkTypeEnum... args) {
        if (value == null || StringUtils.isBlank(String.valueOf(value))) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "like", value, this.isDate, this.format, sqlLinkTypeEnum, "both"));
        return this.e;
    }

    public <F> E in(List<F> value, SqlLinkTypeEnum... args) {
        if (value == null || value.size() == 0) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "in", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E in(F[] value, SqlLinkTypeEnum... args) {
        if (value == null || value.length == 0) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "in", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E notIn(List<F> value, SqlLinkTypeEnum... args) {
        if (value == null || value.size() == 0) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "not in", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public <F> E notIn(F[] value, SqlLinkTypeEnum... args) {
        if (value == null || value.length == 0) {
            return this.e;
        }
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "not in", value, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public E isNull(SqlLinkTypeEnum... args) {
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "is", null, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public E isNotNull(SqlLinkTypeEnum... args) {
        SqlLinkTypeEnum sqlLinkTypeEnum = null;
        if (args.length > 0) {
            sqlLinkTypeEnum = args[0];
        } else {
            sqlLinkTypeEnum = SqlLinkTypeEnum.AND;
        }
        this.t.getRelationModelList().add(
                new RelationModel(this.field, "is not", null, this.isDate, this.format, sqlLinkTypeEnum, null));
        return this.e;
    }

    public E asc() {
        Iterator<OrderByModel> iterator = this.t.getOrderByModelList().iterator();
        while (iterator.hasNext()) {
            OrderByModel element = iterator.next();
            if (this.field.equals(element.getOrderByField())) {
                iterator.remove();
                // 排序只可能有一个，可以直接中断循环
                break;
            }
        }
        this.t.getOrderByModelList().add(new OrderByModel(this.field, OrderTypeEnum.ASC));
        return this.e;
    }

    public E desc() {
        Iterator<OrderByModel> iterator = this.t.getOrderByModelList().iterator();
        while (iterator.hasNext()) {
            OrderByModel element = iterator.next();
            if (this.field.equals(element.getOrderByField())) {
                iterator.remove();
                // 排序只可能有一个，可以直接中断循环
                break;
            }
        }
        this.t.getOrderByModelList().add(new OrderByModel(this.field, OrderTypeEnum.DESC));
        return this.e;
    }

    public void clearCnd() {
        Iterator<RelationModel> cndIterator = this.t.getRelationModelList().iterator();
        while (cndIterator.hasNext()) {
            RelationModel element = cndIterator.next();
            if (this.field.equals(element.getFieldName())) {
                cndIterator.remove();
            }
        }
    }

    public void clearOb() {
        Iterator<OrderByModel> iterator = this.t.getOrderByModelList().iterator();
        while (iterator.hasNext()) {
            OrderByModel element = iterator.next();
            if (this.field.equals(element.getOrderByField())) {
                iterator.remove();
                // 排序只可能有一个，可以直接中断循环
                break;
            }
        }
    }

    public void clear() {
        Iterator<RelationModel> cndIterator = this.t.getRelationModelList().iterator();
        while (cndIterator.hasNext()) {
            RelationModel element = cndIterator.next();
            if (this.field.equals(element.getFieldName())) {
                cndIterator.remove();
            }
        }
        Iterator<OrderByModel> obIterator = this.t.getOrderByModelList().iterator();
        while (obIterator.hasNext()) {
            OrderByModel element = obIterator.next();
            if (this.field.equals(element.getOrderByField())) {
                obIterator.remove();
                // 排序只可能有一个，可以直接中断循环
                break;
            }
        }
    }

    public T core() {
        return this.t;
    }

    public E builder() {
        return this.e;
    }
}
